package com.hilton.tigershark;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.hilton.net.UrlUtils;
import com.hilton.tigershark.UriHandler.UrlData;
import com.hilton.tigershark.bookmarks.BrowserBookmarksAdapter;

import android.app.SearchManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Picture;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.webkit.WebIconDatabase;
import android.webkit.WebView;

public class Utility {
    private static final String LOGTAG = null;

    public static void shareUrlLink(Context ctx, String url) {
	// See if this site has been visited before
	StringBuilder sb = new StringBuilder(BrowserBridge.BookmarkColumns.URL
		+ " = ");
	DatabaseUtils.appendEscapedSQLString(sb, url);
	Cursor c = ctx.getContentResolver().query(BrowserBridge.BOOKMARKS_URI,
		BrowserBridge.HISTORY_PROJECTION, sb.toString(), null, null);
	if (c.moveToFirst()) {
	    // The site has been visited before, so grab the
	    // info from the database.
	    Bitmap favicon = null;
	    Bitmap thumbnail = null;
	    String linkTitle = c
		    .getString(BrowserBridge.HISTORY_PROJECTION_TITLE_INDEX);
	    byte[] data = c
		    .getBlob(BrowserBridge.HISTORY_PROJECTION_FAVICON_INDEX);
	    if (data != null) {
		favicon = BitmapFactory.decodeByteArray(data, 0, data.length);
	    }
	    data = c.getBlob(BrowserBridge.HISTORY_PROJECTION_THUMBNAIL_INDEX);
	    if (data != null) {
		thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
	    }
	    Utility.shareWebpage(ctx, linkTitle, url, favicon, thumbnail);
	} else {
	    BrowserBridge.sendString(ctx, url, ctx.getString(R.string.choosertitle_sharevia));
	}
    }
    /**
     * Share a page, providing the title, url, favicon, and a screenshot.  Uses
     * an {@link Intent} to launch the Activity chooser.
     * @param c Context used to launch a new Activity.
     * @param title Title of the page.  Stored in the Intent with
     *          {@link Intent#EXTRA_SUBJECT}
     * @param url URL of the page.  Stored in the Intent with
     *          {@link Intent#EXTRA_TEXT}
     * @param favicon Bitmap of the favicon for the page.  Stored in the Intent
     *          with {@link BrowserApplication#EXTRA_SHARE_FAVICON}
     * @param screenshot Bitmap of a screenshot of the page.  Stored in the
     *          Intent with {@link BrowserApplication#EXTRA_SHARE_SCREENSHOT}
     */
    public static final void shareWebpage(Context c, String title, String url,
            Bitmap favicon, Bitmap screenshot) {
        Intent send = new Intent(Intent.ACTION_SEND);
        send.setType("text/plain");
        send.putExtra(Intent.EXTRA_TEXT, url);
        send.putExtra(Intent.EXTRA_SUBJECT, title);
        send.putExtra(BrowserBridge.EXTRA_SHARE_FAVICON, favicon);
        send.putExtra(BrowserBridge.EXTRA_SHARE_SCREENSHOT, screenshot);
        try {
            c.startActivity(Intent.createChooser(send, c.getString(
                    R.string.choosertitle_sharevia)));
        } catch(android.content.ActivityNotFoundException ex) {
            // if no app handles it, do nothing
        }
    }

    /**
     * Values for the size of the thumbnail created when taking a screenshot.
     * Lazily initialized.  Instead of using these directly, use
     * getDesiredThumbnailWidth() or getDesiredThumbnailHeight().
     */
    private static int THUMBNAIL_WIDTH = 0;
    private static int THUMBNAIL_HEIGHT = 0;

    /**
     * Return the desired width for thumbnail screenshots, which are stored in
     * the database, and used on the bookmarks screen.
     * @param context Context for finding out the density of the screen.
     * @return int desired width for thumbnail screenshot.
     */
    /* package */ public static int getDesiredThumbnailWidth(Context context) {
        if (THUMBNAIL_WIDTH == 0) {
            float density = context.getResources().getDisplayMetrics().density;
            THUMBNAIL_WIDTH = (int) (90 * density);
            THUMBNAIL_HEIGHT = (int) (80 * density);
        }
        return THUMBNAIL_WIDTH;
    }

    /**
     * Return the desired height for thumbnail screenshots, which are stored in
     * the database, and used on the bookmarks screen.
     * @param context Context for finding out the density of the screen.
     * @return int desired height for thumbnail screenshot.
     */
    /* package */ static int getDesiredThumbnailHeight(Context context) {
        // To ensure that they are both initialized.
        getDesiredThumbnailWidth(context);
        return THUMBNAIL_HEIGHT;
    }
    
    public static Bitmap createScreenshot(WebView view, Context ctx) {
        Picture thumbnail = view.capturePicture();
        if (thumbnail == null) {
            return null;
        }
        Bitmap bm = Bitmap.createBitmap(getDesiredThumbnailWidth(ctx),
                getDesiredThumbnailHeight(ctx), Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bm);
        // May need to tweak these values to determine what is the
        // best scale factor
        int thumbnailWidth = thumbnail.getWidth();
        int thumbnailHeight = thumbnail.getHeight();
        float scaleFactorX = 1.0f;
        float scaleFactorY = 1.0f;
        if (thumbnailWidth > 0) {
            scaleFactorX = (float) getDesiredThumbnailWidth(ctx) /
                    (float)thumbnailWidth;
        } else {
            return null;
        }

        if (view.getWidth() > view.getHeight() &&
                thumbnailHeight < view.getHeight() && thumbnailHeight > 0) {
            // If the device is in landscape and the page is shorter
            // than the height of the view, stretch the thumbnail to fill the
            // space.
            scaleFactorY = (float) getDesiredThumbnailHeight(ctx) /
                    (float)thumbnailHeight;
        } else {
            // In the portrait case, this looks nice.
            scaleFactorY = scaleFactorX;
        }

        canvas.scale(scaleFactorX, scaleFactorY);

        thumbnail.draw(canvas);
        return bm;
    }
    
    public static UrlData getUrlDataFromIntent(Intent intent) {
        String url = "";
        Map<String, String> headers = null;
        if (intent == null) {
            return new UrlData(url, headers, intent);
        }
        final String action = intent.getAction();
        if (Intent.ACTION_VIEW.equals(action)) {
            url = UrlUtils.smartUrlFilter(intent.getData());
            if (url != null && url.startsWith("http")) {
                final Bundle pairs = intent.getBundleExtra(BrowserBridge.EXTRA_HEADERS);
                if (pairs != null && !pairs.isEmpty()) {
                    Iterator<String> iter = pairs.keySet().iterator();
                    headers = new HashMap<String, String>();
                    while (iter.hasNext()) {
                        String key = iter.next();
                        headers.put(key, pairs.getString(key));
                    }
                }
            }
        } else if (Intent.ACTION_SEARCH.equals(action)
                || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
                || Intent.ACTION_WEB_SEARCH.equals(action)) {
            url = intent.getStringExtra(SearchManager.QUERY);
            if (url != null) {
                // In general, we shouldn't modify URL from Intent.
                // But currently, we get the user-typed URL from search box as well.
                url = UrlUtils.fixUrl(url);
                url = UrlUtils.smartUrlFilter(url);
            }
        }
        return new UrlData(url, headers, intent);
    }
    
    /**
     * @param url The URL to build a title version of the URL from.
     * @return The title version of the URL or null if fails.
     * The title version of the URL can be either the URL hostname,
     * or the hostname with an "https://" prefix (for secure URLs),
     * or an empty string if, for example, the URL in question is a
     * file:// URL with no hostname.
     */
    public static String buildTitleUrl(String url) {
        String titleUrl = null;

        if (url != null) {
            try {
                // parse the url string
                URL urlObj = new URL(url);
                if (urlObj != null) {
                    titleUrl = "";

                    String protocol = urlObj.getProtocol();
                    String host = urlObj.getHost();

                    if (host != null && 0 < host.length()) {
                        titleUrl = host;
                        if (protocol != null) {
                            // if a secure site, add an "https://" prefix!
                            if (protocol.equalsIgnoreCase("https")) {
                                titleUrl = protocol + "://" + host;
                            }
                        }
                    }
                }
            } catch (MalformedURLException e) {}
        }

        return titleUrl;
    }

    static void updateScreenshot(WebView view, Context ctx) {
	if (view == null) {
	    return;
	}
        // If this is a bookmarked site, add a screenshot to the database.
        // FIXME: When should we update?  Every time?
        // FIXME: Would like to make sure there is actually something to
        // draw, but the API for that (WebViewCore.pictureReady()) is not
        // currently accessible here.

        final Bitmap bm = Utility.createScreenshot(view, ctx);
        if (bm == null) {
            return;
        }

        final ContentResolver cr = ctx.getContentResolver();
        final String url = view.getUrl();
        final String originalUrl = view.getOriginalUrl();

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... unused) {
                Cursor c = null;
                try {
                    c = BrowserBookmarksAdapter.queryBookmarksForUrl(
                            cr, originalUrl, url, true);
                    if (c != null) {
                        if (c.moveToFirst()) {
                            ContentValues values = new ContentValues();
                            final ByteArrayOutputStream os
                                    = new ByteArrayOutputStream();
                            bm.compress(Bitmap.CompressFormat.PNG, 100, os);
                            values.put(BrowserBridge.BookmarkColumns.THUMBNAIL,
                                    os.toByteArray());
                            do {
                                cr.update(ContentUris.withAppendedId(
                                        BrowserBridge.BOOKMARKS_URI, c.getInt(0)),
                                        values, null, null);
                            } while (c.moveToNext());
                        }
                    }
                } catch (IllegalStateException e) {
                    // Ignore
                } finally {
                    if (c != null) c.close();
                }
                return null;
            }
        }.execute();
    }
    
    static void retainIconsOnStartup(Context ctx) {
        final WebIconDatabase db = WebIconDatabase.getInstance();
        db.open(ctx.getDir("icons", 0).getPath());
        Cursor c = null;
        try {
            c = BrowserBridge.getAllBookmarks(ctx.getContentResolver());
            if (c.moveToFirst()) {
                int urlIndex = c.getColumnIndex(BrowserBridge.BookmarkColumns.URL);
                do {
                    String url = c.getString(urlIndex);
                    db.retainIconForPageUrl(url);
                } while (c.moveToNext());
            }
        } catch (IllegalStateException e) {
            Log.e(LOGTAG, "retainIconsOnStartup", e);
        } finally {
            if (c!= null) c.close();
        }
    }
    
    public static class ClearThumbnails extends AsyncTask<File, Void, Void> {
        private static final String LOGTAG = "ClearThumbnails";

	@Override
        public Void doInBackground(File... files) {
            if (files != null) {
                for (File f : files) {
                    if (!f.delete()) {
                      Log.e(LOGTAG, f.getPath() + " was not deleted");
                    }
                }
            }
            return null;
        }
    }
}
